/**
 * Provider Validator
 * Validates API provider configurations
 */

const BaseValidator = require('./base-validator');

class ProviderValidator extends BaseValidator {
  constructor(options = {}) {
    super('provider', {
      strict: false,
      testMode: false,
      allowExtraFields: true,
      ...options
    });
  }

  /**
   * Perform provider validation
   * @param {Object} provider - Provider configuration
   * @param {Object} context - Validation context
   * @returns {Object} Validation result
   */
  performValidation(provider, context = {}) {
    if (!provider || typeof provider !== 'object') {
      return this.failure('Provider configuration must be a valid object', [{
        field: 'provider',
        message: 'Must be an object',
        value: provider
      }]);
    }

    const errors = [];
    const sanitized = { ...provider };

    // Validate required fields
    const requiredFields = ['base', 'api_key', 'models'];
    for (const field of requiredFields) {
      if (!this.hasField(provider, field)) {
        errors.push({
          field,
          message: `Required field '${field}' is missing`,
          value: provider[field]
        });
      }
    }

    // Validate base URL
    if (provider.base) {
      const baseValidation = this.validateBaseURL(provider.base);
      if (!baseValidation.valid) {
        errors.push(...baseValidation.errors);
      } else {
        sanitized.base = baseValidation.value;
      }
    }

    // Validate API key
    if (provider.api_key !== undefined) {
      const apiKeyValidation = this.validateAPIKey(provider.api_key);
      if (!apiKeyValidation.valid) {
        errors.push(...apiKeyValidation.errors);
      } else {
        sanitized.api_key = apiKeyValidation.value;
      }
    }

    // Validate models
    if (provider.models !== undefined) {
      const modelsValidation = this.validateModels(provider.models);
      if (!modelsValidation.valid) {
        errors.push(...modelsValidation.errors);
      } else {
        sanitized.models = modelsValidation.value;
      }
    }

    // Validate optional fields
    const optionalFields = ['timeout', 'max_retries', 'rate_limit'];
    for (const field of optionalFields) {
      if (provider[field] !== undefined) {
        const validation = this.validateOptionalField(field, provider[field]);
        if (!validation.valid) {
          errors.push(...validation.errors);
        } else {
          sanitized[field] = validation.value;
        }
      }
    }

    // Check for unexpected fields
    if (this.options.strict && !this.options.allowExtraFields) {
      const allowedFields = [...requiredFields, ...optionalFields];
      const unexpectedFields = Object.keys(provider).filter(field => !allowedFields.includes(field));
      if (unexpectedFields.length > 0) {
        errors.push({
          field: 'extra_fields',
          message: `Unexpected fields: ${unexpectedFields.join(', ')}`,
          value: unexpectedFields
        });
      }
    }

    if (errors.length > 0) {
      return this.failure('Provider validation failed', errors);
    }

    return this.success(sanitized);
  }

  /**
   * Check if object has field
   * @param {Object} obj - Object to check
   * @param {string} field - Field name
   * @returns {boolean} Whether field exists
   */
  hasField(obj, field) {
    return obj && obj.hasOwnProperty(field) && obj[field] !== undefined && obj[field] !== null;
  }

  /**
   * Validate base URL
   * @param {string} baseURL - Base URL to validate
   * @returns {Object} Validation result
   */
  validateBaseURL(baseURL) {
    if (typeof baseURL !== 'string') {
      return {
        valid: false,
        errors: [{
          field: 'base',
          message: 'Base URL must be a string',
          value: baseURL
        }]
      };
    }

    // In test mode, allow mock URLs
    if (this.options.testMode) {
      if (baseURL.startsWith('mock://') || baseURL.startsWith('test://')) {
        return { valid: true, value: baseURL };
      }
    }

    // Basic URL validation
    const urlPattern = /^https?:\/\/.+/;
    if (!urlPattern.test(baseURL)) {
      return {
        valid: false,
        errors: [{
          field: 'base',
          message: 'Base URL must be a valid HTTP/HTTPS URL',
          value: baseURL
        }]
      };
    }

    return { valid: true, value: baseURL };
  }

  /**
   * Validate API key
   * @param {string} apiKey - API key to validate
   * @returns {Object} Validation result
   */
  validateAPIKey(apiKey) {
    if (typeof apiKey !== 'string') {
      return {
        valid: false,
        errors: [{
          field: 'api_key',
          message: 'API key must be a string',
          value: apiKey
        }]
      };
    }

    // In test mode, allow empty or test keys
    if (this.options.testMode) {
      if (apiKey === '' || apiKey.startsWith('test_') || apiKey.startsWith('mock_')) {
        return { valid: true, value: apiKey };
      }
    }

    // For production, allow empty API keys for unconfigured providers
    // Only validate that if a key is provided, it's not just whitespace
    if (apiKey.trim() === '' && apiKey !== '') {
      return {
        valid: false,
        errors: [{
          field: 'api_key',
          message: 'API key cannot be only whitespace',
          value: apiKey
        }]
      };
    }

    return { valid: true, value: apiKey };
  }

  /**
   * Validate models array
   * @param {Array} models - Models array to validate
   * @returns {Object} Validation result
   */
  validateModels(models) {
    if (!Array.isArray(models)) {
      return {
        valid: false,
        errors: [{
          field: 'models',
          message: 'Models must be an array',
          value: models
        }]
      };
    }

    const errors = [];
    const sanitizedModels = [];

    for (let i = 0; i < models.length; i++) {
      const model = models[i];
      const modelValidation = this.validateModel(model, i);

      if (!modelValidation.valid) {
        errors.push(...modelValidation.errors);
      } else {
        sanitizedModels.push(modelValidation.value);
      }
    }

    if (errors.length > 0) {
      return {
        valid: false,
        errors
      };
    }

    return { valid: true, value: sanitizedModels };
  }

  /**
   * Validate individual model
   * @param {Object} model - Model to validate
   * @param {number} index - Model index
   * @returns {Object} Validation result
   */
  validateModel(model, index) {
    // 支持字符串格式的模型名称
    if (typeof model === 'string') {
      if (model.trim() === '') {
        return {
          valid: false,
          errors: [{
            field: `models[${index}]`,
            message: 'Model name cannot be empty',
            value: model
          }]
        };
      }
      return { valid: true, value: model.trim() };
    }

    // 如果是对象格式，检查是否包含name字段
    if (model && typeof model === 'object') {
      const errors = [];

      // 检查name字段
      if (!model.name || typeof model.name !== 'string' || model.name.trim() === '') {
        errors.push({
          field: `models[${index}].name`,
          message: 'Model must have a valid name',
          value: model.name
        });
      }

      if (errors.length > 0) {
        return {
          valid: false,
          errors
        };
      }

      return { valid: true, value: { ...model, name: model.name.trim() } };
    }

    return {
      valid: false,
      errors: [{
        field: `models[${index}]`,
        message: 'Model must be a string or object with name field',
        value: model
      }]
    };
  }

  /**
   * Validate optional field
   * @param {string} field - Field name
   * @param {*} value - Field value
   * @returns {Object} Validation result
   */
  validateOptionalField(field, value) {
    switch (field) {
      case 'timeout':
        if (typeof value !== 'number' || value < 1000 || value > 300000) {
          return {
            valid: false,
            errors: [{
              field,
              message: 'Timeout must be a number between 1000 and 300000',
              value
            }]
          };
        }
        break;

      case 'max_retries':
        if (typeof value !== 'number' || value < 0 || value > 10) {
          return {
            valid: false,
            errors: [{
              field,
              message: 'Max retries must be a number between 0 and 10',
              value
            }]
          };
        }
        break;

      case 'rate_limit':
        if (typeof value !== 'object' || value === null) {
          return {
            valid: false,
            errors: [{
              field,
              message: 'Rate limit must be an object',
              value
            }]
          };
        }
        break;

      default:
        // Unknown optional field, skip validation in non-strict mode
        break;
    }

    return { valid: true, value };
  }

  /**
   * Create a test-friendly provider configuration
   * @param {Object} overrides - Configuration overrides
   * @returns {Object} Test configuration
   */
  createTestConfig(overrides = {}) {
    return {
      base: 'https://api.test.com',
      api_key: 'test_api_key',
      models: [
        {
          id: 'test-model',
          name: 'Test Model',
          type: 'vision',
          capabilities: ['image_analysis'],
          max_tokens: 4096,
          supports_vision: true,
          enabled: true
        }
      ],
      timeout: 30000,
      max_retries: 3,
      ...overrides
    };
  }

  /**
   * Get suggestion for provider validation error
   * @param {Object} error - Validation error
   * @returns {string} Suggestion message
   */
  getSuggestion(error) {
    switch (error.field) {
      case 'base':
        return 'Provide a valid HTTP/HTTPS URL for the API base (e.g., "https://api.openai.com")';
      case 'api_key':
        return 'Provide a valid API key string. For testing, use "test_api_key"';
      case 'models':
        return 'Ensure models is an array of model objects with id, name, and type fields';
      default:
        return `Check the ${error.field} field for correct format and value`;
    }
  }
}

module.exports = ProviderValidator;